package cn.org.donald.framework.service.impl;

import cn.org.donald.framework.constant.EncodeConstant;
import cn.org.donald.framework.constant.HttpStatus;
import cn.org.donald.framework.constant.TableConstant;
import cn.org.donald.framework.pojo.dto.ChangePwdDto;
import cn.org.donald.framework.pojo.dto.UserDto;
import cn.org.donald.framework.pojo.vo.HttpResult;
import cn.org.donald.framework.service.SysUserService;
import cn.org.donald.framework.util.*;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import cn.org.donald.framework.pojo.dto.PageDto;
import cn.org.donald.mapper.RoleMapper;
import cn.org.donald.mapper.UserMapper;
import cn.org.donald.mapper.UserRoleMapper;
import cn.org.donald.pojo.entity.system.Role;
import cn.org.donald.pojo.entity.system.User;
import cn.org.donald.pojo.entity.system.UserRole;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author ： Donald
 * @date ： 2020/10/17 15:54
 * @description：
 */
@Service(interfaceClass = SysUserService.class, version = "1.0.0",group = "donald")
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 用户注册
     * @param user
     * @return
     */
    public int insert(User user) {
        //明文 MD5 + Salt + Hash散列 加密

        //生成随机盐
        String saltValue = EncodeUtil.getSalt();

        //生成加密密码
        String encodePassword = EncodeUtil.getEncodePassword(user.getPassword(), saltValue);

        user.setSaltValue(saltValue);
        user.setPassword(encodePassword);

        return userMapper.insert(user);
    }

    /**
     * 根据userName查询user信息
     *
     * @param userName
     * @return
     */
    @Override
    public User findByUserName(String userName) {
        //用mybatis-plus的QueryWrapper条件构造器

        /**
         * 这里只对userName实现了登录,理论上还要查询多个登录名(比如手机、邮箱等)
         */
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userName);
        return userMapper.selectOne(queryWrapper);
    }

    /**
     * 用户名是否存在
     *
     * @param userName
     * @return
     */
    @Override
    public boolean isExistByUserName(String userName) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",userName);
        List<User> list = userMapper.selectList(queryWrapper);
        return !list.isEmpty();
    }

    /**
     * 手机号是否存在
     *
     * @param phone
     * @return
     */
    @Override
    public boolean isExistByPhone(String phone) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone",phone);
        List<User> list = userMapper.selectList(queryWrapper);
        return !list.isEmpty();
    }

    /**
     * email是否存在
     *
     * @param email
     * @return
     */
    @Override
    public boolean isExistByEmail(String email) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        List<User> list = userMapper.selectList(queryWrapper);
        return !list.isEmpty();
    }

    /**
     * 用户列表分页查询
     * @param pageDto
     * @return
     */
    @Override
    public IPage<User> findAllPage(PageDto<User> pageDto) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(pageDto.getQuery());
        IPage<User> userIPage = userMapper.selectPage(pageDto, queryWrapper);
        List<User> records = userIPage.getRecords();
        records.forEach(record -> record.setPhone(StringUtil.hideMainlandPhone(record.getPhone())));
        userIPage.setRecords(records);
        return userIPage;
    }


    /**
     * 用户名称是否为超级管理员用户
     * @param id
     * @return
     */
    @Override
    public boolean isAdminUser(Long id) {
        User user = userMapper.selectById(id);
        return user.getUserName().equals(TableConstant.VALUE_ADMIN_USER_NAME);
    }


    /**
     * 根据id删除用户
     * @param id
     * @return
     */
    @Override
    public int removeById(Long id) {
        return userMapper.deleteById(id);
    }

    /**
     * 根据id更新用户信息
     * @param userDto
     * @return
     */
    @Override
    public int edit(UserDto userDto) {
        User user = new User();
        BeanUtil.copyProperties(userDto,user);
        return userMapper.updateById(user);
    }

    /**
     * 新增管理员
     *
     * @param user
     * @return
     */
    @Transactional
    @Override
    public int insertAdminUser(User user) {
        int rows = 0;
        //新增角色,返回id
        int rowUser = userMapper.insert(user);
        if (rowUser>0){
            QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("role_name", TableConstant.VALUE_ADMIN_NAME);
            Role role = roleMapper.selectOne(queryWrapper);
            UserRole userRole = new UserRole();
            userRole.setRoleId(role.getId());
            userRole.setUserId(user.getId());
            rows = userRoleMapper.insert(userRole);
        }
        return rows;
    }

    @Override
    public User findById(Long userId) {
        User user = userMapper.selectById(userId);
        // 去掉密码
        user.setPassword(null);
        // 去掉随机盐
        user.setSaltValue(null);
        // 隐藏大陆手机
        user.setPhone(StringUtil.hideMainlandPhone(user.getPhone()));
        return user;
    }

    /**
     * 修改密码的判断条件：
     * 获取前端传来的verifiedToken(JWT) 解析获取userId,再根据verifiedToken获取的验证状态,为ok则更新密码
     * 满足HttpServletRequest 的userId 和verifiedToken的userId相等,并且验证状态为ok
     * @param changePwdDto
     * @param id
     * @return
     */
    @Override
    @SuppressWarnings("unchecked")
    public boolean changePwd(ChangePwdDto changePwdDto, Long id) {
        if (StringUtil.isEmpty(changePwdDto.getPassword())||StringUtil.isEmpty(changePwdDto.getVerifiedToken())) {
            return false;
        }
        try {
            String verifyResult = (String) redisTemplate.opsForValue().get(changePwdDto.getVerifiedToken());
            DecodedJWT verify = JwtUtil.verify(changePwdDto.getVerifiedToken());
            String userId = verify.getClaim("userId").asString();

            // 根据verifiedToken获取验证状态
            if (!StringUtil.isEmpty(userId) && userId.equals(id+"") && EncodeConstant.VERIFY_STATUS_OK.equals(verifyResult)){
                //删除redis的token
                redisTemplate.delete(changePwdDto.getVerifiedToken());
                User user = new User();
                String salt = EncodeUtil.getSalt();
                user.setId(id);
                user.setSaltValue(salt);
                String password = changePwdDto.getPassword();
                System.out.println("password = "+password);
                String encodePassword = EncodeUtil.getEncodePassword(password, salt);
                System.out.println("encodePassword = " + encodePassword);
                user.setPassword(encodePassword);
                int rows = userMapper.updateById(user);
                return rows > 0;
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return false;
    }

    @Override
    public User findByPhone(String phone) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone",phone);
        return userMapper.selectOne(queryWrapper);
    }

    /**
     * 验证成功后生成获取验证码的verifiedToken
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public HashMap<String, Object> verified(Long userId) {
        String token = JwtUtil.getToken(userId + "", 30);
        redisTemplate.opsForValue().set(token, EncodeConstant.VERIFY_STATUS_OK,30, TimeUnit.MINUTES);
        HashMap<String, Object> map = new HashMap<>();
        map.put("verifiedToken",token);
        return map;
    }

    @Override
    public int editPerson(UserDto userDto) {
        User user = new User();
        BeanUtil.copyProperties(userDto,user);
        user.setUserName(null);
        return userMapper.updateById(user);
    }

    @Override
    public HttpResult sendSmsVerify(String phone, Long userId) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone",phone);
        queryWrapper.eq("id",userId);
        Integer count = userMapper.selectCount(queryWrapper);
        if (count>0){
            String verifyToken = SendMsgUtil.sendPhoneVerify(userId, phone, 5);
            HashMap<String, Object> map = new HashMap<>();
            map.put("verifyToken",verifyToken);
            return new HttpResult(map);
        }
        return new HttpResult(HttpStatus.INTERNAL_SERVER_ERROR,"手机号不正确");
    }


}
